/*
 * Copyright (C) 2012  Romain DUBOIS
 * 
 * This file is part of NeMoS - Network and Modular Software
 * 
 * NeMoS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * NeMoS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with NeMoS.  If not, see <http://www.gnu.org/licenses/>.
 */
package nemos.launch.internal;

import java.io.IOException;
import java.io.PrintStream;
import java.util.Date;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.log.LogEntry;
import org.osgi.service.log.LogListener;
import org.osgi.service.log.LogReaderService;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

/**
 * LaunchLogger : The simple launch logger.
 * 
 * <p>
 * This logger is only used during the launch process. Once the framework is
 * launched, this logger is turned off. This log file is written in the bundle
 * data space under the specified name ({@link #LAUNCH_LOG_FILE_PROP}).
 * </p>
 * 
 * @author Romain DUBOIS
 */
public class LaunchLogger implements LogListener {

    /** The launch log file property */
    private static final String LAUNCH_LOG_FILE_PROP = "nemos.launch.log.file"; //$NON-NLS-1$

    /** The output file printer */
    private PrintStream mPrinter;

    /** The log reader tracker */
    private final ServiceTracker mTracker;

    /**
     * Constructor
     * 
     * @param pContext
     *            The bundle context
     */
    public LaunchLogger(final BundleContext pContext) {
        super();

        final String lOutputFile = pContext.getProperty(LAUNCH_LOG_FILE_PROP);
        if (lOutputFile != null) {
            try {
                mPrinter = new PrintStream(pContext.getDataFile(lOutputFile));
            } catch (final IOException e) {
                mPrinter = System.out;
            }
        }

        mTracker = new ServiceTracker(pContext, LogReaderService.class.getName(),
                new ServiceTrackerCustomizer() {

                    @Override
                    public Object addingService(final ServiceReference pReference) {
                        final Object lService = pContext.getService(pReference);
                        ((LogReaderService) lService).addLogListener(LaunchLogger.this);
                        return lService;
                    }

                    @Override
                    public void modifiedService(
                            @SuppressWarnings("unused") final ServiceReference pReference,
                            @SuppressWarnings("unused") final Object pService) {
                        // Do nothing
                    }

                    @Override
                    public void removedService(final ServiceReference pReference,
                            final Object pService) {
                        ((LogReaderService) pService).removeLogListener(LaunchLogger.this);
                        pContext.ungetService(pReference);
                    }
                });
        mTracker.open();
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.osgi.service.log.LogListener#logged(org.osgi.service.log.LogEntry)
     */
    @Override
    public synchronized void logged(final LogEntry pEntry) {
        if (mPrinter != null) {
            mPrinter.print(new Date(pEntry.getTime()));
            switch (pEntry.getLevel()) {
                case LogService.LOG_DEBUG:
                    mPrinter.print(" DEBUG ["); //$NON-NLS-1$
                    break;
                case LogService.LOG_INFO:
                    mPrinter.print(" INFO  ["); //$NON-NLS-1$
                    break;
                case LogService.LOG_WARNING:
                    mPrinter.print(" WARN  ["); //$NON-NLS-1$
                    break;
                case LogService.LOG_ERROR:
                    mPrinter.print(" ERROR ["); //$NON-NLS-1$
                    break;
                default:
                    mPrinter.print(" ????? ["); //$NON-NLS-1$
            }
            if (pEntry.getBundle() != null) {
                mPrinter.print(pEntry.getBundle().getSymbolicName());
            }
            mPrinter.print("] "); //$NON-NLS-1$
            mPrinter.println(pEntry.getMessage());
            if (pEntry.getException() != null) {
                pEntry.getException().printStackTrace(mPrinter);
            }
            mPrinter.flush();
        }
    }

    /**
     * Stop the logger (initialization ended).
     */
    public synchronized void stop() {
        if (mPrinter != null && mPrinter != System.out) {
            mPrinter.close();
            mPrinter = null;
        }

        final Object[] lServices = mTracker.getServices();
        if (lServices != null) {
            for (final Object lService : lServices) {
                ((LogReaderService) lService).removeLogListener(this);
            }
        }
        mTracker.close();
    }
}
